#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include "Mlib.h"
#include "pthread.h"
#include "string.h"
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>

#define PORT 8888
#define webpath "../web/index.html"
#define web_404path "../web/web_404.html"
#define webresourcepath "../web/resource"
#define websrcpath "../web"
const char start_logo[]="//\n\
//                          _ooOoo_                          //\n\
//                         o8888888o                         //\n\
//                         88\" . \"88                         //\n\
//                         (| ^_^ |)                         //\n\
//                         O\\  =  /O                         //\n\
//                      ____/`---'\\____                      //\n\
//                    .'  \\\\|     |//  `.                    //\n\
//                   /  \\\\|||  :  |||//  \\                   //\n\
//                  /  _||||| -:- |||||-  \\                  //\n\
//                  |   | \\\\\\  -  /// |   |                  //\n\
//                  | \\_|  ''\\---/''  |   |                  //\n\
//                  \\  .-\\__  `-`  ___/-. /                  //\n\
//                ___`. .'  /--.--\\  `. . ___                //\n\
//               ."" '<  `.___\\_<|>_/___.'  >'"".                //\n\
//            | | :  `- \\`.;`\\ _ /`;.`/ - ` : | |            //\n\
//            \\  \\ `-.   \\_ __\\ /__ _/   .-` /  /            //\n\
//     ========`-.____`-.___\\_____/___.-`____.-'========     //\n\
//                          `=---='                          //\n\
//     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^     //\n\
//           佛祖保佑       永不宕机     永无BUG             //\n\
\n";
enum Response_Type{
    Type_json,  //回应josn
    Type_doc,   //回应文件
    Type_str    //回应单纯字符串
};
long get_file_size(const char *filename) {
    FILE *file = fopen(filename, "rb");
    if (!file) {
        perror("Error opening file");
        return -1;
    }
    fseek(file, 0, SEEK_END);
    long length = ftell(file);
    fclose(file);

    return length;
}

void* fun(void* clint_fd)
{
    int fd=*((int*)clint_fd);
    char buff[1024]={0};
    char respose[1024*500],respose_head[1024];
    int re=read(fd,buff,sizeof(buff));              //读取连接请求
 //   printf("[fun ] read is: %d \r\n",re);
    if(re<0)
        goto end ;
    //printf("%s\n",buff);
    char url[100]={0};         //url
    char method[100]={0};      //请求
    char resousepath[100]={0}; //资源路径
    char *rcode="200";        //回应状态码
    char* type= "text/html";
    char* status ="OK";
    int Response_type=Type_str;
    long file_len =0;
    printf("[fun ]recv:\n");
    printf("%s \r\n",buff);
    sscanf(buff,"%s %s HTTP/1.1",method,url);
    printf("[fun ] method is %s url is: %s \r\n",method,url);
    if(strstr(method,"POST")){//post 请求



    }
    else if(strstr(method,"GET")){ //get 请求
        if(strstr(url,".ico")) //图标
        {
            sprintf(resousepath,"%s%s",webresourcepath,url);
            file_len =  get_file_size(resousepath);
            if(file_len != -1){
                rcode="200";
                type="image/x-icon";
            }
            Response_type =Type_doc;
        } else if(strcmp(url,"/")==0){//主页
            sprintf(resousepath,"%s",webpath);
            file_len =  get_file_size(resousepath);
            if(file_len != -1){
                rcode="200";
                type="text/html";
            }
            type="text/html";
            Response_type =Type_doc;
        }else if(strstr(url,"/src")){//src
            sprintf(resousepath,"%s%s",websrcpath,url);
            file_len =  get_file_size(resousepath);
            if(file_len != -1){
                rcode="200";
                if(strstr(url,".css"))//表明类型
                    type="text/css";
                else if(strstr(url,".js"))
                    type="text/javascript";
                else
                    type="text/html";
            }
            Response_type =Type_doc;
        }
        else                           //若出现其他返回404
        {
            rcode="404";
            status="Not Found";
            type="text/html";
            Response_type =Type_doc;
            sprintf(resousepath,"%s",web_404path);
        }
    }
    else{   //未知的请求类型
        rcode="404";
        status="Not Found";
        type="text/html";
        Response_type =Type_doc;
        sprintf(resousepath,"%s",web_404path);
    }
    if(Response_type == Type_doc){//回复文件
        if(file_len == -1){ //如果找不到文件 回复404
            rcode="404";
            status="Not Found";
            type="text/html";
            Response_type =Type_doc;
            sprintf(resousepath,"%s",web_404path);
        }
        int file_fd=open(resousepath,O_RDONLY);
        if(file_fd==-1)
        {
            printf("file open error filename:%s\n",resousepath);
            goto end;
            return NULL;
        }
        sprintf(respose_head,"HTTP/1.1 %s %s\nContent-Type:%s\n",rcode,status,type);      //响应头
        ssize_t write_size =write(fd,respose_head,strlen(respose_head));
        sprintf(respose_head,"Content-Length: %ld\n\n",file_len);      //可选部分
        write_size =write(fd,respose_head,strlen(respose_head));
        if(write_size == -1)
        {
            printf("[write] ERROR \r\n");
            goto end;
        }
        while(read(file_fd,respose,file_len)>0) {                      //相应主体
            write_size= write(fd, respose, file_len);
            if(write_size == -1)
            {
                printf("[write] ERROR \r\n");
                goto end;
            }
        }
    }else if(Response_type == Type_json){//回复json
        sprintf(respose_head,"HTTP/1.1 %s %s\nContent-Type:%s\n\n",rcode,status,type);      //响应头
        ssize_t write_size =write(fd,respose_head,strlen(respose_head));
        if(write_size == -1)
        {
            printf("[write] ERROR \r\n");
            goto end;
        }
    }else if(Response_type == Type_str){//回复字符串
        sprintf(respose_head,"HTTP/1.1 %s %s\nContent-Type:%s\n\n",rcode,status,type);      //响应头
        ssize_t write_size =write(fd,respose_head,strlen(respose_head));
        if(write_size == -1)
        {
            printf("[write] ERROR \r\n");
            goto end;
        }

    }

    end:
    close(fd);
    printf("[fun ] connect close:\n");
//    close(file_fd);
}
int main() {
    char timestr[30]={0};
    get_localtm(timestr,30);
    printf("%s",start_logo);
    printf("%s web_server start!\n",timestr);
    int sever_fd =socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in sever_addr={0};
    sever_addr.sin_family=AF_INET;
    sever_addr.sin_addr.s_addr=INADDR_ANY;
    sever_addr.sin_port= htons(PORT);
    if(bind(sever_fd,(struct sockaddr*)&sever_addr, sizeof(sever_addr))==-1)
    {
        printf("[web_server] bind error %m\n");
        exit(-1);
    }
    if(listen(sever_fd,10)==-1)
    {
        printf("[web_server] listen error %m\n");
        exit(-2);
    }
    printf("%s init succeess!\n",timestr);
    while(1)
    {
        struct sockaddr_in clint_addr={0};
        int len=0;
        int clint_fd= accept(sever_fd, (struct sockaddr*)&clint_addr, (socklen_t *)&len);   //接收连接
        pthread_t tid;
        if(clint_fd==-1)
        {
            printf("clint_fd error  clint_fd:%d\n",clint_fd);
            break;
        }
        else{
            struct sockaddr_in address;
            socklen_t addrlen = sizeof(address);
            getpeername(clint_fd, (struct sockaddr *)&address, &addrlen);
            printf("%s %s connect !\n",timestr,inet_ntoa(*(struct in_addr *)(&(address.sin_addr))));
            pthread_create(&tid,NULL,fun,&clint_fd);            //创建线程，处理接受的连接
        }


    }
    return 0;
}
